本文將提及以下內容
有時候我們得要等到畫面渲染之後才進行Javascript的操控,例如在input的欄位,實現聚焦效果(focus),我們需要確切只到實際的DOM,因此這時候就得透過useRef用來存取實際DOM元素了。
根據react beta版本的官方文件解釋
useRef is a React Hook that lets you reference a value that’s not needed for rendering.
大致意思是useRef是讓你參照一個值卻不會發生重新渲染的hook。
我們可以嘗試著在useRef當中帶入"hello"字串
觀看以下範例
import { useRef } from 'react'
function App() {
const helloRef = useRef("hello")
console.log(helloRef);
return (
<div>
App
</div>
)
}
export default App
最後呈現下圖
可以看到上述印出helloRef會印出一個物件,裡面有一個current的key,物件的值是"hello"。
這裡搭配使用useState、useEffect、useRef來記得渲染的次數,我們撰寫一下範例
import { useState, useRef, useEffect } from 'react'
function App() {
const [text, setText] = useState("");
const number = useRef(0);
useEffect(() => {
number.current = number.current + 1;
});
return (
<>
<input
type="text"
value={text}
onChange={
(e) => setText(e.target.value)
}
/>
<h1>總共渲染起次{number.current}</h1>
</>
);
}
export default App
由於useEffect的第二個值不帶入參數表示每次重新渲染後會執行useEffect裡面的事情,因此我們將number進行加總,不會因為重新渲染導致該current的值不一樣,換句話說,每次渲染的物件是同一個,因此我們在text輸入了a~j總共有十個英文字母就會渲染10次,如下圖
我們可以透過useRef搭配屬性ref來存取DOM,換句話說,他提供了一個管道使我們可以參照到實際的HTMLelement。
function App() {
const divRefContrainer = useRef(null);
return (
<div className="test" ref={divRefContrainer}>嗨</div>
)
}
上面的語法相當於我們在使用vanilla javascript的下面的語法
const divElement = document.querySelector(".test")
平時React將大多數的操作行為儲存在memory當中,等到先行比對Virtual Dom開始進行diff演算法,最後再實際掛載到真實的DOM當中,但有些事件是必須先渲染完後才能進行。
例如執行focus效果必須擁有真實的input DOM元素才能將效果呈現出來。我們可以觀看以下範例
import { useRef } from 'react'
function App() {
const inputRef = useRef(null)
const handClick = () => {
inputRef.current.focus();
}
return (
<>
<input
type="text"
ref={inputRef}
/>
<button onClick={handClick}>按我聚焦</button>
</>
);
}
export default App
需要注意的地方,不要過度使用,大多數情形我們希望react來管理狀態,透過useRef將其掛載在DOM上面會導致state和資料不統一的情形,觀看以下範例
import { useRef, useState } from 'react'
function App() {
const inputRef = useRef(null);
const [inputValue, setInputValue] = useState("")
const handClick = () => {
inputRef.current.focus();
inputRef.current.value = '為什麼被改變了'
}
console.log("沒有觸發rerender");
return (
<>
<input
type="text"
ref={inputRef}
value={inputValue}
onChange={e => setInput(e.target.value)}
/>
<div>我輸入的東西{inputValue}</div>
<button onClick={handClick}>按我聚焦</button>
</>
);
}
export default App
通常在我們輸入字母到畫面上的input的時候應當會因為onChage事件,所以畫面會印出我所輸入的字母。
這時候如果我們改用按我聚焦的方式改變畫面上的input內容時卻不會顯示
如下圖
這是因為我們透過useRef的方式將value輸入到input的元素當中,也沒有觸發reRender,而且inputValue和 inputRef.current.value並不一致,所以最後就沒有顯示在畫面上了。
另外文章有錯誤的部分歡迎糾正,希望有幫助到大家,